use async_graphql::{Context, Result, Object, SimpleObject, InputObject};
use redis::aio::MultiplexedConnection;
use sea_orm::DatabaseConnection;
use serde::{Deserialize, Serialize};
use crate::entity::{sys_auth_authority};
use crate::handler::system_handler::{bind_authority_to_user, bind_role_to_user, create_authority, create_role, create_scheduled_task, delete_authority, delete_role, delete_scheduled_task, get_authorities, get_authority_by_id, get_role_by_id, get_roles, get_scheduled_task_by_id, get_scheduled_tasks, update_role, update_scheduled_task};
use crate::graphql::AuthGuard;
// 自定义角色对象
#[derive(Debug, Clone, Serialize, Deserialize, SimpleObject)]
pub struct SysAuthRoleObject {
    pub id: String,
    pub role_name: String,
    pub authorities: Vec<SysAuthAuthorityObject>,
    pub create_time: String,
    pub update_time: String,
}

// 自定义权限对象
#[derive(Debug, Clone, Serialize, Deserialize, SimpleObject)]
pub struct SysAuthAuthorityObject {
    pub id: String,
    pub authority_name: String,
    pub create_time: String,
    pub update_time: String,
}

impl From<sys_auth_authority::Model> for SysAuthAuthorityObject {
    fn from(model: sys_auth_authority::Model) -> Self {
        SysAuthAuthorityObject {
            id: model.id.to_string(),
            authority_name: model.authority_name,
            create_time: model.create_time.to_string(),
            update_time: model.update_time.to_string(),
        }
    }
}


// 添加定时任务的输入对象
#[derive(Debug, Clone, InputObject)]
pub struct SysScheduledTaskInput {
    pub task_name: String,
    pub task_type: String,
    pub cron_expression: Option<String>,
    pub status: String,
    pub next_run_time: String,
    pub last_run_time: Option<String>,
    pub max_retries: u32,
    pub shard_key: Option<String>,
    pub task_parameter: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, SimpleObject)]
pub struct SysScheduledTaskObject {
    pub id: String,
    pub create_time: String,
    pub update_time: String,
    pub task_name: String,
    pub task_type: String,
    pub cron_expression: Option<String>,
    pub status: String,
    pub next_run_time: String,
    pub last_run_time: Option<String>,
    pub retry_count: u32,
    pub max_retries: u32,
    pub shard_key: Option<String>,
    pub task_parameter: Option<String>,
}

#[derive(Default)]
pub struct SysAuthQuery;

#[Object]
impl SysAuthQuery {

    /// 查询所有角色
    #[graphql(guard = "AuthGuard(\"sys:auth:role:select\")")]
    async fn roles(&self, ctx: &Context<'_>) -> Result<Vec<SysAuthRoleObject>> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        get_roles(db.clone(), conn.clone()).await
    }

    /// 根据ID查询角色
    #[graphql(guard = "AuthGuard(\"sys:auth:role:select_by_id\")")]
    async fn role_by_id(&self, ctx: &Context<'_>, id: u64) -> Result<Option<SysAuthRoleObject>> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        get_role_by_id(db.clone(), conn.clone(), id).await
    }

    /// 查询所有权限
    #[graphql(guard = "AuthGuard(\"sys:auth:authority:select\")")]
    async fn authorities(&self, ctx: &Context<'_>) -> Result<Vec<SysAuthAuthorityObject>> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        get_authorities(db.clone(), conn.clone()).await
    }

    /// 根据ID查询权限
    #[graphql(guard = "AuthGuard(\"sys:auth:authority:select_by_id\")")]
    async fn authority_by_id(&self, ctx: &Context<'_>, id: u64) -> Result<Option<SysAuthAuthorityObject>> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        get_authority_by_id(db.clone(),conn.clone(), id).await
    }

    /// 查询所有定时任务
    #[graphql(guard = "AuthGuard(\"sys:scheduled:task:select\")")]
    async fn scheduled_tasks(&self, ctx: &Context<'_>) -> Result<Vec<SysScheduledTaskObject>> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        get_scheduled_tasks(db.clone(), conn.clone()).await
    }

    /// 根据ID查询定时任务
    #[graphql(guard = "AuthGuard(\"sys:scheduled:task:select_by_id\")")]
    async fn scheduled_task_by_id(&self, ctx: &Context<'_>, id: u64) -> Result<Option<SysScheduledTaskObject>> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        get_scheduled_task_by_id(db.clone(), conn.clone(), id).await
    }

}


// 新增角色的输入对象
#[derive(Debug, Clone, InputObject)]
pub struct SysAuthRoleInput {
    pub role_name: String,
    pub authority_ids: Vec<String>,
}


// 更新角色的输入对象
#[derive(Debug, Clone, InputObject)]
pub struct SysAuthRoleUpdateInput {
    pub id: String,
    pub role_name: String,
    pub authority_ids: Vec<String>,
}


// 用户绑定权限输入对象
#[derive(Debug, Clone, InputObject)]
pub struct SysAuthUserAuthorityInput {
    pub user_id: String,
    pub authority_ids: Vec<String>,
}

// 用户绑定角色输入对象
#[derive(Debug, Clone, InputObject)]
pub struct SysAuthUserRoleInput {
    pub user_id: String,
    pub role_ids: Vec<String>,
}

// 更新定时任务的输入对象
#[derive(Debug, Clone, InputObject)]
pub struct SysScheduledTaskUpdateInput {
    pub id: String,
    pub task_name: String,
    pub task_type: String,
    pub cron_expression: Option<String>,
    pub status: String,
    pub next_run_time: String,
    pub last_run_time: Option<String>,
    pub max_retries: u32,
    pub shard_key: Option<String>,
    pub task_parameter: Option<String>,
}

#[derive(Default)]
pub struct SysAuthMutation;

#[Object]
impl SysAuthMutation {
    /// 新增权限
    #[graphql(guard = "AuthGuard(\"sys:auth:authority:create\")")]
    async fn add_authority(&self, ctx: &Context<'_>, authority_name: String) -> Result<SysAuthAuthorityObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        create_authority(db, conn,  authority_name).await
    }

    /// 新增角色
    #[graphql(guard = "AuthGuard(\"sys:auth:role:create\")")]
    async fn add_role(&self, ctx: &Context<'_>, input: SysAuthRoleInput) -> Result<SysAuthRoleObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;

        create_role(db, conn, input.role_name, input.authority_ids).await
    }

    /// 删除角色
    #[graphql(guard = "AuthGuard(\"sys:auth:role:delete\")")]
    async fn delete_role(&self, ctx: &Context<'_>, id: u64) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        delete_role(&db, id).await
    }

    /// 删除权限
    #[graphql(guard = "AuthGuard(\"sys:auth:authority:delete\")")]
    async fn delete_authority(&self, ctx: &Context<'_>, id: u64) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        delete_authority(&db, id).await
    }

    /// 更新角色
    #[graphql(guard = "AuthGuard(\"sys:auth:role:update\")")]
    async fn update_role(&self, ctx: &Context<'_>, input: SysAuthRoleUpdateInput) -> Result<SysAuthRoleObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        update_role(&db, &conn, input.id, input.role_name, input.authority_ids).await
    }

    /// 用户绑定权限
    #[graphql(guard = "AuthGuard(\"sys:auth:user:authority:bind\")")]
    async fn bind_user_authority(&self, ctx: &Context<'_>, input: SysAuthUserAuthorityInput) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        bind_authority_to_user(&db, input.user_id, input.authority_ids).await
    }

    /// 用户绑定角色
    #[graphql(guard = "AuthGuard(\"sys:auth:user:role:bind\")")]
    async fn bind_user_role(&self, ctx: &Context<'_>, input: SysAuthUserRoleInput) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        bind_role_to_user(&db, input.user_id, input.role_ids).await
    }

    /// 添加定时任务
    #[graphql(guard = "AuthGuard(\"sys:scheduled:task:create\")")]
    async fn add_scheduled_task(&self, ctx: &Context<'_>, input: SysScheduledTaskInput) -> Result<SysScheduledTaskObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        create_scheduled_task(db, conn, input).await
    }

    /// 删除定时任务
    #[graphql(guard = "AuthGuard(\"sys:scheduled:task:delete\")")]
    async fn delete_scheduled_task(&self, ctx: &Context<'_>, id: u64) -> Result<bool> {
        let db = ctx.data::<DatabaseConnection>()?;
        delete_scheduled_task(&db, id).await
    }

    /// 更新定时任务
    #[graphql(guard = "AuthGuard(\"sys:scheduled:task:update\")")]
    async fn update_scheduled_task(&self, ctx: &Context<'_>, input: SysScheduledTaskUpdateInput) -> Result<SysScheduledTaskObject> {
        let db = ctx.data::<DatabaseConnection>()?;
        let conn = ctx.data::<MultiplexedConnection>()?;
        update_scheduled_task(&db, &conn, input).await
    }
}


